/**
 * creation: 4-okt-2007
 */
package org.jfonia.harmony;

import java.util.ArrayList;

/**
 * Converts chordtype-information into lilypond code. 
 * <p>
 * Note: doesn't use shorthands "m", "aug" or "dim". All harmonies are written
 * using numbers (alterations). E.g. minor -> "3-.5" instead of "m"
 * 
 * @author Wijnand
 *
 */
public class LilypondChordNotationStyle implements ChordNotationStyle
{
	// helper:
	private String makeString(ChordAlteration chordAlteration)
	{
		StringBuilder sb = new StringBuilder();
		sb.append(Integer.toString(chordAlteration.getDegree()));
		
		int at = chordAlteration.getAlterationType();
		if (chordAlteration.getDegree()==7)
			at++;	// in lilypond 7 is flat by default, so - is bb and + is M7
			
		if (at==ChordType.PERFECT)	// == MAJOR
			;	// nothing
		else if (at==ChordType.LOWERED)
			sb.append('-');
		else if (at==ChordType.RAISED)
			sb.append('+');
		else if (at==ChordType.LOWERED_AND_RAISED)
			sb.append('+');	// impossible in lilypond (TODO: warning?)
		else 
			sb.append("???");		// TODO: better treatment
		
		return sb.toString();
	}
	
	
	public String makeString(ChordTypeNotation chordTypeNotation)
	{
		StringBuilder sb = new StringBuilder();
		sb.append(chordTypeNotation.getKind());		// == "" 
		
		ArrayList<ChordAlteration> altList = chordTypeNotation.getChordAlterationList();
		
		ArrayList<ChordAlteration> additions = new ArrayList<ChordAlteration>();
		ArrayList<ChordAlteration> removals = new ArrayList<ChordAlteration>();
		if (altList!=null)
			for (int i=0; i<altList.size(); i++)
				if (altList.get(i).getAlterationType() == ChordType.OMIT) 
					removals.add(altList.get(i));
				else
					additions.add(altList.get(i));
	
		// first additions, separated by dots
		if (additions.size() > 0)
		{
			sb.append(makeString(additions.get(0)));
			for (int i=1; i<additions.size(); i++)
			{
				sb.append('.');
				sb.append(makeString(additions.get(i)));
			}
		}
		// then removals, preceded by single '^' and separated by dots:
		if (removals.size() > 0)
		{
			sb.append('^');
			sb.append(removals.get(0).getDegree());
			for (int i=1; i<removals.size(); i++)
			{
				sb.append('.');
				sb.append(removals.get(i).getDegree());
			}
		}
		
		
		return sb.toString();

	}

	public ChordTypeNotation makeTypeNotation(ChordType chordType)
	{
		String kind = "";
		ArrayList<ChordAlteration> alterationList = new ArrayList<ChordAlteration>();
		
		int ct3 = chordType.getType3();
		int ct5 = chordType.getType5();
		int ct7 = chordType.getType7(); 
		int ct9 = chordType.getType9(); 
		int ct11 = chordType.getType11();
		int ct13 = chordType.getType13(); 
		
		//sus2:
		if (ct3 == ChordType.OMIT)
		{
			if (ct9==ChordType.MAJOR 
					&& ct11!=ChordType.PERFECT) // in case of sus4: leave 9	
			{
				ct9 = ChordType.OMIT;
				alterationList.add(new ChordAlteration(2, ChordType.MAJOR));
			}
		}

		//3:
		alterationList.add(new ChordAlteration(3, ct3));

		//sus4:
		if (ct3 == ChordType.OMIT)
		{
			if (ct11==ChordType.PERFECT)	
			{
				ct11 = ChordType.OMIT;
				alterationList.add(new ChordAlteration(4, ChordType.PERFECT));
			}
		}
		
		//5:
		alterationList.add(new ChordAlteration(5, ct5));
		
		//add6:
		if (ct7 == ChordType.OMIT)
		{
			if (ct13==ChordType.MAJOR)	
			{
				ct13 = ChordType.OMIT;
				alterationList.add(new ChordAlteration(6, ChordType.MAJOR));
			}
		}
		
		int highest = 5;
		if (ct7 != ChordType.OMIT)
			highest = 7;
		if (ct9 != ChordType.OMIT)
			highest = 9;
		if (ct11 != ChordType.OMIT)
			highest = 11;
		if (ct13 != ChordType.OMIT)
			highest = 13;
		
		if (! (ct7==ChordType.OMIT && highest<7) )
			alterationList.add(new ChordAlteration(7, ct7));
		
		if (! (ct9==ChordType.OMIT && highest<9) )
			alterationList.add(new ChordAlteration(9, ct9));

		if (! (ct11==ChordType.OMIT && highest<11) )
			alterationList.add(new ChordAlteration(11, ct11));
		
		if (! (ct13==ChordType.OMIT && highest<13) )
			alterationList.add(new ChordAlteration(13, ct13));
		
//		System.out.println("check:" + highest);
//		for (ChordAlteration alt:alterationList) 
//			System.out.println(alt.toString());
		
		return new ChordTypeNotation(kind, alterationList);
	}

}
